home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / src / linux-headers-2.6.28-15 / scripts / kconfig / lxdialog / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  2008-12-24  |  16.7 KB  |  656 lines

  1. /*
  2.  *  util.c
  3.  *
  4.  *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
  5.  *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
  6.  *
  7.  *  This program is free software; you can redistribute it and/or
  8.  *  modify it under the terms of the GNU General Public License
  9.  *  as published by the Free Software Foundation; either version 2
  10.  *  of the License, or (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. #include "dialog.h"
  23.  
  24. struct dialog_info dlg;
  25.  
  26. static void set_mono_theme(void)
  27. {
  28.     dlg.screen.atr = A_NORMAL;
  29.     dlg.shadow.atr = A_NORMAL;
  30.     dlg.dialog.atr = A_NORMAL;
  31.     dlg.title.atr = A_BOLD;
  32.     dlg.border.atr = A_NORMAL;
  33.     dlg.button_active.atr = A_REVERSE;
  34.     dlg.button_inactive.atr = A_DIM;
  35.     dlg.button_key_active.atr = A_REVERSE;
  36.     dlg.button_key_inactive.atr = A_BOLD;
  37.     dlg.button_label_active.atr = A_REVERSE;
  38.     dlg.button_label_inactive.atr = A_NORMAL;
  39.     dlg.inputbox.atr = A_NORMAL;
  40.     dlg.inputbox_border.atr = A_NORMAL;
  41.     dlg.searchbox.atr = A_NORMAL;
  42.     dlg.searchbox_title.atr = A_BOLD;
  43.     dlg.searchbox_border.atr = A_NORMAL;
  44.     dlg.position_indicator.atr = A_BOLD;
  45.     dlg.menubox.atr = A_NORMAL;
  46.     dlg.menubox_border.atr = A_NORMAL;
  47.     dlg.item.atr = A_NORMAL;
  48.     dlg.item_selected.atr = A_REVERSE;
  49.     dlg.tag.atr = A_BOLD;
  50.     dlg.tag_selected.atr = A_REVERSE;
  51.     dlg.tag_key.atr = A_BOLD;
  52.     dlg.tag_key_selected.atr = A_REVERSE;
  53.     dlg.check.atr = A_BOLD;
  54.     dlg.check_selected.atr = A_REVERSE;
  55.     dlg.uarrow.atr = A_BOLD;
  56.     dlg.darrow.atr = A_BOLD;
  57. }
  58.  
  59. #define DLG_COLOR(dialog, f, b, h) \
  60. do {                               \
  61.     dlg.dialog.fg = (f);       \
  62.     dlg.dialog.bg = (b);       \
  63.     dlg.dialog.hl = (h);       \
  64. } while (0)
  65.  
  66. static void set_classic_theme(void)
  67. {
  68.     DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
  69.     DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
  70.     DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
  71.     DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
  72.     DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
  73.     DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
  74.     DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
  75.     DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
  76.     DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
  77.     DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
  78.     DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
  79.     DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
  80.     DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
  81.     DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
  82.     DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
  83.     DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
  84.     DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
  85.     DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
  86.     DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
  87.     DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
  88.     DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
  89.     DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
  90.     DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
  91.     DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
  92.     DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
  93.     DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
  94.     DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
  95.     DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
  96.     DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
  97. }
  98.  
  99. static void set_blackbg_theme(void)
  100. {
  101.     DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
  102.     DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
  103.     DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
  104.     DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
  105.     DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
  106.  
  107.     DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
  108.     DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
  109.     DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
  110.     DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
  111.     DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
  112.     DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
  113.  
  114.     DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
  115.     DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
  116.  
  117.     DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
  118.     DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
  119.     DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
  120.  
  121.     DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
  122.  
  123.     DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
  124.     DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
  125.  
  126.     DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
  127.     DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
  128.  
  129.     DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
  130.     DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
  131.     DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
  132.     DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
  133.  
  134.     DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
  135.     DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
  136.  
  137.     DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
  138.     DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
  139. }
  140.  
  141. static void set_bluetitle_theme(void)
  142. {
  143.     set_classic_theme();
  144.     DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
  145.     DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
  146.     DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
  147.     DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
  148.     DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
  149.     DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
  150.     DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
  151.  
  152. }
  153.  
  154. /*
  155.  * Select color theme
  156.  */
  157. static int set_theme(const char *theme)
  158. {
  159.     int use_color = 1;
  160.     if (!theme)
  161.         set_bluetitle_theme();
  162.     else if (strcmp(theme, "classic") == 0)
  163.         set_classic_theme();
  164.     else if (strcmp(theme, "bluetitle") == 0)
  165.         set_bluetitle_theme();
  166.     else if (strcmp(theme, "blackbg") == 0)
  167.         set_blackbg_theme();
  168.     else if (strcmp(theme, "mono") == 0)
  169.         use_color = 0;
  170.  
  171.     return use_color;
  172. }
  173.  
  174. static void init_one_color(struct dialog_color *color)
  175. {
  176.     static int pair = 0;
  177.  
  178.     pair++;
  179.     init_pair(pair, color->fg, color->bg);
  180.     if (color->hl)
  181.         color->atr = A_BOLD | COLOR_PAIR(pair);
  182.     else
  183.         color->atr = COLOR_PAIR(pair);
  184. }
  185.  
  186. static void init_dialog_colors(void)
  187. {
  188.     init_one_color(&dlg.screen);
  189.     init_one_color(&dlg.shadow);
  190.     init_one_color(&dlg.dialog);
  191.     init_one_color(&dlg.title);
  192.     init_one_color(&dlg.border);
  193.     init_one_color(&dlg.button_active);
  194.     init_one_color(&dlg.button_inactive);
  195.     init_one_color(&dlg.button_key_active);
  196.     init_one_color(&dlg.button_key_inactive);
  197.     init_one_color(&dlg.button_label_active);
  198.     init_one_color(&dlg.button_label_inactive);
  199.     init_one_color(&dlg.inputbox);
  200.     init_one_color(&dlg.inputbox_border);
  201.     init_one_color(&dlg.searchbox);
  202.     init_one_color(&dlg.searchbox_title);
  203.     init_one_color(&dlg.searchbox_border);
  204.     init_one_color(&dlg.position_indicator);
  205.     init_one_color(&dlg.menubox);
  206.     init_one_color(&dlg.menubox_border);
  207.     init_one_color(&dlg.item);
  208.     init_one_color(&dlg.item_selected);
  209.     init_one_color(&dlg.tag);
  210.     init_one_color(&dlg.tag_selected);
  211.     init_one_color(&dlg.tag_key);
  212.     init_one_color(&dlg.tag_key_selected);
  213.     init_one_color(&dlg.check);
  214.     init_one_color(&dlg.check_selected);
  215.     init_one_color(&dlg.uarrow);
  216.     init_one_color(&dlg.darrow);
  217. }
  218.  
  219. /*
  220.  * Setup for color display
  221.  */
  222. static void color_setup(const char *theme)
  223. {
  224.     int use_color;
  225.  
  226.     use_color = set_theme(theme);
  227.     if (use_color && has_colors()) {
  228.         start_color();
  229.         init_dialog_colors();
  230.     } else
  231.         set_mono_theme();
  232. }
  233.  
  234. /*
  235.  * Set window to attribute 'attr'
  236.  */
  237. void attr_clear(WINDOW * win, int height, int width, chtype attr)
  238. {
  239.     int i, j;
  240.  
  241.     wattrset(win, attr);
  242.     for (i = 0; i < height; i++) {
  243.         wmove(win, i, 0);
  244.         for (j = 0; j < width; j++)
  245.             waddch(win, ' ');
  246.     }
  247.     touchwin(win);
  248. }
  249.  
  250. void dialog_clear(void)
  251. {
  252.     attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
  253.     /* Display background title if it exists ... - SLH */
  254.     if (dlg.backtitle != NULL) {
  255.         int i;
  256.  
  257.         wattrset(stdscr, dlg.screen.atr);
  258.         mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
  259.         wmove(stdscr, 1, 1);
  260.         for (i = 1; i < COLS - 1; i++)
  261.             waddch(stdscr, ACS_HLINE);
  262.     }
  263.     wnoutrefresh(stdscr);
  264. }
  265.  
  266. /*
  267.  * Do some initialization for dialog
  268.  */
  269. int init_dialog(const char *backtitle)
  270. {
  271.     int height, width;
  272.  
  273.     initscr();        /* Init curses */
  274.     getmaxyx(stdscr, height, width);
  275.     if (height < 19 || width < 80) {
  276.         endwin();
  277.         return -ERRDISPLAYTOOSMALL;
  278.     }
  279.  
  280.     dlg.backtitle = backtitle;
  281.     color_setup(getenv("MENUCONFIG_COLOR"));
  282.  
  283.     keypad(stdscr, TRUE);
  284.     cbreak();
  285.     noecho();
  286.     dialog_clear();
  287.  
  288.     return 0;
  289. }
  290.  
  291. void set_dialog_backtitle(const char *backtitle)
  292. {
  293.     dlg.backtitle = backtitle;
  294. }
  295.  
  296. /*
  297.  * End using dialog functions.
  298.  */
  299. void end_dialog(int x, int y)
  300. {
  301.     /* move cursor back to original position */
  302.     move(y, x);
  303.     refresh();
  304.     endwin();
  305. }
  306.  
  307. /* Print the title of the dialog. Center the title and truncate
  308.  * tile if wider than dialog (- 2 chars).
  309.  **/
  310. void print_title(WINDOW *dialog, const char *title, int width)
  311. {
  312.     if (title) {
  313.         int tlen = MIN(width - 2, strlen(title));
  314.         wattrset(dialog, dlg.title.atr);
  315.         mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
  316.         mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
  317.         waddch(dialog, ' ');
  318.     }
  319. }
  320.  
  321. /*
  322.  * Print a string of text in a window, automatically wrap around to the
  323.  * next line if the string is too long to fit on one line. Newline
  324.  * characters '\n' are replaced by spaces.  We start on a new line
  325.  * if there is no room for at least 4 nonblanks following a double-space.
  326.  */
  327. void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
  328. {
  329.     int newl, cur_x, cur_y;
  330.     int i, prompt_len, room, wlen;
  331.     char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
  332.  
  333.     strcpy(tempstr, prompt);
  334.  
  335.     prompt_len = strlen(tempstr);
  336.  
  337.     /*
  338.      * Remove newlines
  339.      */
  340.     for (i = 0; i < prompt_len; i++) {
  341.         if (tempstr[i] == '\n')
  342.             tempstr[i] = ' ';
  343.     }
  344.  
  345.     if (prompt_len <= width - x * 2) {    /* If prompt is short */
  346.         wmove(win, y, (width - prompt_len) / 2);
  347.         waddstr(win, tempstr);
  348.     } else {
  349.         cur_x = x;
  350.         cur_y = y;
  351.         newl = 1;
  352.         word = tempstr;
  353.         while (word && *word) {
  354.             sp = strchr(word, ' ');
  355.             if (sp)
  356.                 *sp++ = 0;
  357.  
  358.             /* Wrap to next line if either the word does not fit,
  359.                or it is the first word of a new sentence, and it is
  360.                short, and the next word does not fit. */
  361.             room = width - cur_x;
  362.             wlen = strlen(word);
  363.             if (wlen > room ||
  364.                 (newl && wlen < 4 && sp
  365.                  && wlen + 1 + strlen(sp) > room
  366.                  && (!(sp2 = strchr(sp, ' '))
  367.                  || wlen + 1 + (sp2 - sp) > room))) {
  368.                 cur_y++;
  369.                 cur_x = x;
  370.             }
  371.             wmove(win, cur_y, cur_x);
  372.             waddstr(win, word);
  373.             getyx(win, cur_y, cur_x);
  374.             cur_x++;
  375.             if (sp && *sp == ' ') {
  376.                 cur_x++;    /* double space */
  377.                 while (*++sp == ' ') ;
  378.                 newl = 1;
  379.             } else
  380.                 newl = 0;
  381.             word = sp;
  382.         }
  383.     }
  384. }
  385.  
  386. /*
  387.  * Print a button
  388.  */
  389. void print_button(WINDOW * win, const char *label, int y, int x, int selected)
  390. {
  391.     int i, temp;
  392.  
  393.     wmove(win, y, x);
  394.     wattrset(win, selected ? dlg.button_active.atr
  395.          : dlg.button_inactive.atr);
  396.     waddstr(win, "<");
  397.     temp = strspn(label, " ");
  398.     label += temp;
  399.     wattrset(win, selected ? dlg.button_label_active.atr
  400.          : dlg.button_label_inactive.atr);
  401.     for (i = 0; i < temp; i++)
  402.         waddch(win, ' ');
  403.     wattrset(win, selected ? dlg.button_key_active.atr
  404.          : dlg.button_key_inactive.atr);
  405.     waddch(win, label[0]);
  406.     wattrset(win, selected ? dlg.button_label_active.atr
  407.          : dlg.button_label_inactive.atr);
  408.     waddstr(win, (char *)label + 1);
  409.     wattrset(win, selected ? dlg.button_active.atr
  410.          : dlg.button_inactive.atr);
  411.     waddstr(win, ">");
  412.     wmove(win, y, x + temp + 1);
  413. }
  414.  
  415. /*
  416.  * Draw a rectangular box with line drawing characters
  417.  */
  418. void
  419. draw_box(WINDOW * win, int y, int x, int height, int width,
  420.      chtype box, chtype border)
  421. {
  422.     int i, j;
  423.  
  424.     wattrset(win, 0);
  425.     for (i = 0; i < height; i++) {
  426.         wmove(win, y + i, x);
  427.         for (j = 0; j < width; j++)
  428.             if (!i && !j)
  429.                 waddch(win, border | ACS_ULCORNER);
  430.             else if (i == height - 1 && !j)
  431.                 waddch(win, border | ACS_LLCORNER);
  432.             else if (!i && j == width - 1)
  433.                 waddch(win, box | ACS_URCORNER);
  434.             else if (i == height - 1 && j == width - 1)
  435.                 waddch(win, box | ACS_LRCORNER);
  436.             else if (!i)
  437.                 waddch(win, border | ACS_HLINE);
  438.             else if (i == height - 1)
  439.                 waddch(win, box | ACS_HLINE);
  440.             else if (!j)
  441.                 waddch(win, border | ACS_VLINE);
  442.             else if (j == width - 1)
  443.                 waddch(win, box | ACS_VLINE);
  444.             else
  445.                 waddch(win, box | ' ');
  446.     }
  447. }
  448.  
  449. /*
  450.  * Draw shadows along the right and bottom edge to give a more 3D look
  451.  * to the boxes
  452.  */
  453. void draw_shadow(WINDOW * win, int y, int x, int height, int width)
  454. {
  455.     int i;
  456.  
  457.     if (has_colors()) {    /* Whether terminal supports color? */
  458.         wattrset(win, dlg.shadow.atr);
  459.         wmove(win, y + height, x + 2);
  460.         for (i = 0; i < width; i++)
  461.             waddch(win, winch(win) & A_CHARTEXT);
  462.         for (i = y + 1; i < y + height + 1; i++) {
  463.             wmove(win, i, x + width);
  464.             waddch(win, winch(win) & A_CHARTEXT);
  465.             waddch(win, winch(win) & A_CHARTEXT);
  466.         }
  467.         wnoutrefresh(win);
  468.     }
  469. }
  470.  
  471. /*
  472.  *  Return the position of the first alphabetic character in a string.
  473.  */
  474. int first_alpha(const char *string, const char *exempt)
  475. {
  476.     int i, in_paren = 0, c;
  477.  
  478.     for (i = 0; i < strlen(string); i++) {
  479.         c = tolower(string[i]);
  480.  
  481.         if (strchr("<[(", c))
  482.             ++in_paren;
  483.         if (strchr(">])", c) && in_paren > 0)
  484.             --in_paren;
  485.  
  486.         if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
  487.             return i;
  488.     }
  489.  
  490.     return 0;
  491. }
  492.  
  493. /*
  494.  * ncurses uses ESC to detect escaped char sequences. This resutl in
  495.  * a small timeout before ESC is actually delivered to the application.
  496.  * lxdialog suggest <ESC> <ESC> which is correctly translated to two
  497.  * times esc. But then we need to ignore the second esc to avoid stepping
  498.  * out one menu too much. Filter away all escaped key sequences since
  499.  * keypad(FALSE) turn off ncurses support for escape sequences - and thats
  500.  * needed to make notimeout() do as expected.
  501.  */
  502. int on_key_esc(WINDOW *win)
  503. {
  504.     int key;
  505.     int key2;
  506.     int key3;
  507.  
  508.     nodelay(win, TRUE);
  509.     keypad(win, FALSE);
  510.     key = wgetch(win);
  511.     key2 = wgetch(win);
  512.     do {
  513.         key3 = wgetch(win);
  514.     } while (key3 != ERR);
  515.     nodelay(win, FALSE);
  516.     keypad(win, TRUE);
  517.     if (key == KEY_ESC && key2 == ERR)
  518.         return KEY_ESC;
  519.     else if (key != ERR && key != KEY_ESC && key2 == ERR)
  520.         ungetch(key);
  521.  
  522.     return -1;
  523. }
  524.  
  525. /* redraw screen in new size */
  526. int on_key_resize(void)
  527. {
  528.     dialog_clear();
  529.     return KEY_RESIZE;
  530. }
  531.  
  532. struct dialog_list *item_cur;
  533. struct dialog_list item_nil;
  534. struct dialog_list *item_head;
  535.  
  536. void item_reset(void)
  537. {
  538.     struct dialog_list *p, *next;
  539.  
  540.     for (p = item_head; p; p = next) {
  541.         next = p->next;
  542.         free(p);
  543.     }
  544.     item_head = NULL;
  545.     item_cur = &item_nil;
  546. }
  547.  
  548. void item_make(const char *fmt, ...)
  549. {
  550.     va_list ap;
  551.     struct dialog_list *p = malloc(sizeof(*p));
  552.  
  553.     if (item_head)
  554.         item_cur->next = p;
  555.     else
  556.         item_head = p;
  557.     item_cur = p;
  558.     memset(p, 0, sizeof(*p));
  559.  
  560.     va_start(ap, fmt);
  561.     vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
  562.     va_end(ap);
  563. }
  564.  
  565. void item_add_str(const char *fmt, ...)
  566. {
  567.     va_list ap;
  568.         size_t avail;
  569.  
  570.     avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
  571.  
  572.     va_start(ap, fmt);
  573.     vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
  574.           avail, fmt, ap);
  575.     item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
  576.     va_end(ap);
  577. }
  578.  
  579. void item_set_tag(char tag)
  580. {
  581.     item_cur->node.tag = tag;
  582. }
  583. void item_set_data(void *ptr)
  584. {
  585.     item_cur->node.data = ptr;
  586. }
  587.  
  588. void item_set_selected(int val)
  589. {
  590.     item_cur->node.selected = val;
  591. }
  592.  
  593. int item_activate_selected(void)
  594. {
  595.     item_foreach()
  596.         if (item_is_selected())
  597.             return 1;
  598.     return 0;
  599. }
  600.  
  601. void *item_data(void)
  602. {
  603.     return item_cur->node.data;
  604. }
  605.  
  606. char item_tag(void)
  607. {
  608.     return item_cur->node.tag;
  609. }
  610.  
  611. int item_count(void)
  612. {
  613.     int n = 0;
  614.     struct dialog_list *p;
  615.  
  616.     for (p = item_head; p; p = p->next)
  617.         n++;
  618.     return n;
  619. }
  620.  
  621. void item_set(int n)
  622. {
  623.     int i = 0;
  624.     item_foreach()
  625.         if (i++ == n)
  626.             return;
  627. }
  628.  
  629. int item_n(void)
  630. {
  631.     int n = 0;
  632.     struct dialog_list *p;
  633.  
  634.     for (p = item_head; p; p = p->next) {
  635.         if (p == item_cur)
  636.             return n;
  637.         n++;
  638.     }
  639.     return 0;
  640. }
  641.  
  642. const char *item_str(void)
  643. {
  644.     return item_cur->node.str;
  645. }
  646.  
  647. int item_is_selected(void)
  648. {
  649.     return (item_cur->node.selected != 0);
  650. }
  651.  
  652. int item_is_tag(char tag)
  653. {
  654.     return (item_cur->node.tag == tag);
  655. }
  656.